#ifndef CHAINSAW_COMMON_COMMAND_H
#define CHAINSAW_COMMON_COMMAND_H

#include <memory>
#include <string>
#include <vector>
#include <type_traits>
#include "stringtool.h"
#include "print.h"

namespace chainsaw
{
    class command
    {
    public:
        // --word xxx -> [word(=)xxx]
        // --word=xxx -> [word(=)xxx]
        // -c -> [c]
        // -C -> [C]
        // -cxy ->[c;x;y]
        // -C[space]xxx -> [C(=)xxx]
        // -cxy mmm -> [c;x;y(=)mmm]
        command(std::string s);

        command(int argc, char **argv);

        // command(std::vector<std::string> arg);

        //
        bool find(std::string option) const;

        //
        std::vector<std::string> get_option_arguments(std::string option) const;

        template <typename T>
        void add_option(std::string const &opt, T &ref) const
        {
            stringtool tool(opt);
            std::vector<std::string> opts = tool.split(tool.find_all(','));
            for (auto &t : opts)
            {
                while (t.front() == '-')
                {
                    t.erase(t.begin());
                }
            }
            
            int find_index = -1;
            for (int i = 0; i < opts.size(); ++i)
            {
                if (find(opts[i]))
                {
                    find_index = i;
                    break;
                }
            }

            if constexpr (std::is_same_v<T, std::string>)
            {
                if(find_index != -1)
                {
                    auto ret = get_option_arguments(opts[find_index]);
                    if(ret.size())
                    {
                        ref = ret[0];
                    }
                }
            }
            else if constexpr (std::is_same_v<T, bool>)
            {
                if(!ref)
                    ref = find_index != -1;
            }
            else if constexpr (std::is_same_v<T, int>)
            {
                if(find_index != -1)
                {
                    auto ret = get_option_arguments(opts[find_index]);
                    if(ret.size())
                    {
                        try
                        {
                            ref = std::stoi(ret[0]);
                        }
                        catch (...)
                        {
                            warn("Failed to convert to int");
                        }
                    }
                }
            }
            else if constexpr (std::is_same_v<T, std::vector<std::string>>)
            {
                if(find_index != -1)
                {
                    ref = get_option_arguments(opts[find_index]);
                }
            }
        }

        // print all command
        void print() const;

        struct Node
        {
            std::string value;
            std::vector<std::string> args;
        };

    private:
        void check(std::vector<std::string> const &data) const;

        void parse(std::vector<std::string> const &data);

    private:
        std::vector<Node> m_all;
    };
} // namespace chainsaw

#endif // !CHAINSAW_COMMON_COMMAND_H
